package com.apes.fn.scm.lossSale;

import com.apes.crm.business.model.InsuranceCompanyDetail;
import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.service.FixedLossToForeign;
import com.apes.fn.scm.insuranceRules.InsuranceRule;
import com.apes.fn.scm.insuranceRules.InsuranceRuleService;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.processor.idempotent.AntiHeavy;
import com.apes.framework.plugin.esb.processor.idempotent.AntiHeavyRepository;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * 这里是重新根据界面输入的保险公司和金额，重新生成销售
 * 执行逻辑：
 *      1.查找之前的对保险公司销售的逻辑，用 "调整的商品" 退掉销售部分，然后再做返厂
 *      2.根据界面输入的保险公司，再次使用 "调整的商品" 重新做销售
 * @Author wuq
 * @Date 2021-12-10
 */
@Service
public class InsuranceSaleReturnService extends DomainService {

    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private TaxService taxService;

    public void process(LossSaleAdjust lossSaleAdjust){
        // 退销售部分
        returnSaleProcess(lossSaleAdjust);

        // 重新销售部分
        reSaleProcess(lossSaleAdjust);
    }

    private void returnSaleProcess(LossSaleAdjust lossSaleAdjust){
        // 退回时判断老保险公司
        InsuranceRule insuranceRule = SpringManager.getBean(InsuranceRuleService.class)
                .findByDeptAndInsuranceCompany(lossSaleAdjust.getDept(), lossSaleAdjust.getOldInsuranceCompany());
        if (Objects.isNull(insuranceRule)) throw new RuntimeException("没有找到对应的车险规则，请检查！");

        // 获取保险公司客户
        InsuranceCompanyDetail companyDetail = SpringManager.getBean(FixedLossToForeign.class)
                .getInsuranceCompanyToClient(lossSaleAdjust.getOldInsuranceCompany(), lossSaleAdjust.getDept());
        // 零售单数据
        RetailOrder retailOrder = SpringManager.getBean(RetailOrderRepository.class).findOne(lossSaleAdjust.getRetailId());

        if (insuranceRule.getCompany().getId().equals(lossSaleAdjust.getCompany().getId())) {
            /**  原单：直接对保险公司销售  **/
            Voucher saleReturnVoucher = returnSaleVoucher(retailOrder.getAmtTotal(), lossSaleAdjust.getDept(), lossSaleAdjust.getCompany(), companyDetail.getClient(), lossSaleAdjust);
            returnPurchase(0d, lossSaleAdjust.getCompany(), saleReturnVoucher, lossSaleAdjust);
        } else {
            /** 原单：找合同公司对保险公司销售  **/
            // 合同公司
            Voucher insuranceReturnVoucher = returnSaleVoucher(retailOrder.getAmtTotal(), insuranceRule.getDept(), insuranceRule.getCompany(), companyDetail.getClient(), lossSaleAdjust);
            returnPurchase(retailOrder.getAmtTotal(), lossSaleAdjust.getCompany(), insuranceReturnVoucher, lossSaleAdjust);

            // 定损公司
            Voucher saleReturnVoucher = returnSaleVoucher(retailOrder.getAmtTotal(), lossSaleAdjust.getDept(), lossSaleAdjust.getCompany(), insuranceRule.getCompany(), lossSaleAdjust);
            returnPurchase(0d, lossSaleAdjust.getCompany(), saleReturnVoucher, lossSaleAdjust);
        }
    }

    private Voucher returnSaleVoucher(double amt, Dept dept, PartyRole company, PartyRole partner, LossSaleAdjust lossSaleAdjust){
        Voucher voucher = getVoucher(lossSaleAdjust);
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.SALE_RETURN);
        voucher.setClassification(VoucherType.LOSS_SALE_RETURN);

        voucher.setDept(dept);
        voucher.setCompany(company);
        voucher.setPartner(partner.getParty().getPartyRoleByType("Customer"));

        // 明细处理
        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = getVoucherItem(lossSaleAdjust);
        voucherItem.setPriceUnit(amt);
        voucherItem.setProductQty(-1);
        voucherItem.setOwner(voucher.getCompany());

        Tax tax = taxService.getSaleTax(company, voucherItem.getProduct());
        voucherItem.setTax(tax);

        voucherItems.add(voucherItem);
        voucher.setVoucherItems(voucherItems);

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));

        return voucher;
    }

    private void returnPurchase(double amt, PartyRole supplier, Voucher saleReturnVoucher, LossSaleAdjust lossSaleAdjust){
        Voucher voucher = getVoucher(lossSaleAdjust);
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.PURCHASE_RETURN);
        voucher.setDept(saleReturnVoucher.getDept());
        voucher.setCompany(saleReturnVoucher.getCompany());
        voucher.setPartner(supplier.getParty().getPartyRoleByType("Supplier"));

        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = getVoucherItem(lossSaleAdjust);
        voucherItem.setPriceUnit(amt);
        voucherItem.setProductQty(-1);
        voucherItem.setOwner(saleReturnVoucher.getCompany());

        Tax tax = taxService.getPurchaseTax(voucher.getCompany(), voucher.getPartner(), voucherItem.getProduct());   //供应商进项税
        voucherItem.setTax(tax);

        // 获原销售退回批次
        VoucherInventory voucherInventory = voucherInventoryRepository.findAll(
                JpaDsl.toCriteriaByEq("voucher.id", saleReturnVoucher.getId(), "voucherItem", saleReturnVoucher.getVoucherItems().iterator().next()))
                .stream().findFirst().get();
        voucherItem.setInventoryBatch(voucherInventory.getInventoryBatch());

        //  增加冻结数量
        inventoryService.changeFrostQty(voucherInventory.getInventoryBatch(), voucherItem.getUom(), 1,
                voucherInventory.getInventoryBatch().getCompany(),
                lossSaleAdjust.getInnerBusinessType(), lossSaleAdjust.getId(), lossSaleAdjust.getId(), "赋能定损调整销售冻结批次");

        voucherItems.add(voucherItem);
        voucher.setVoucherItems(voucherItems);

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        if (amt > 0) {
            invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));
        }
    }

    private Voucher getVoucher(LossSaleAdjust lossSaleAdjust){
        Voucher voucher = new Voucher();
        voucher.setInventoryMode(InventoryMode.IM_OWN);     //设置库存模式：自有
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销
        voucher.setCustomerExpand(lossSaleAdjust.getCustomerExpand().getId());

        voucher.setClerk(lossSaleAdjust.getApproveUID());
        voucher.setScene(null);
        voucher.setOrigin(lossSaleAdjust.getLossQuotationId());
        voucher.setOriginBusinessType(LossQuotation.class.getSimpleName());
        voucher.setSource(lossSaleAdjust.getId());
        voucher.setSourceBusinessType(lossSaleAdjust.getInnerBusinessType());
        return voucher;
    }

    private VoucherItem getVoucherItem(LossSaleAdjust lossSaleAdjust){
        VoucherItem voucherItem = new VoucherItem();
        Product product = productRepository.findById("0002291509").get();
        voucherItem.setProduct(product);
        voucherItem.setUom(product.getUom());
        voucherItem.setTax(product.getTax());

        voucherItem.setDiscount(0d);
        voucherItem.setOriginItemId(lossSaleAdjust.getId());
        voucherItem.setSourceItemId(lossSaleAdjust.getId());
        return voucherItem;
    }


    private void reSaleProcess(LossSaleAdjust lossSaleAdjust){
        // 再次销售时判断新保险公司
        InsuranceRule insuranceRule = SpringManager.getBean(InsuranceRuleService.class)
                .findByDeptAndInsuranceCompany(lossSaleAdjust.getDept(), lossSaleAdjust.getNewInsuranceCompany());
        if (insuranceRule ==null) throw new RuntimeException("没有找到"+ lossSaleAdjust.getNewInsuranceCompany().getName()+"的门店定损规则");

        // 获取保险公司客户
        InsuranceCompanyDetail companyDetail = SpringManager.getBean(FixedLossToForeign.class)
                .getInsuranceCompanyToClient(lossSaleAdjust.getNewInsuranceCompany(), lossSaleAdjust.getDept());

        if (insuranceRule.getCompany().getId().equals(lossSaleAdjust.getCompany().getId())) {
            //  直接对保险公司销售
            Voucher purVoucher =createPurchaseVoucher(0d, lossSaleAdjust.getDept(), lossSaleAdjust.getCompany(), lossSaleAdjust.getCompany(), lossSaleAdjust);
            createSaleVoucher(purVoucher, companyDetail.getClient(), lossSaleAdjust);
        } else {
            /** 找合同公司对保险公司销售  **/

            // 定损方卖给合同公司
            Voucher purVoucher =createPurchaseVoucher(0d, lossSaleAdjust.getDept(), lossSaleAdjust.getCompany(), lossSaleAdjust.getCompany(), lossSaleAdjust);
            createSaleVoucher(purVoucher, insuranceRule.getCompany(), lossSaleAdjust);

            // 合同公司卖给保险公司
            Voucher purContractVoucher =createPurchaseVoucher(lossSaleAdjust.getAmount(), insuranceRule.getDept(),
                    insuranceRule.getCompany(), lossSaleAdjust.getCompany(), lossSaleAdjust);
            createSaleVoucher(purContractVoucher, companyDetail.getClient(), lossSaleAdjust);
        }
    }

    private Voucher createPurchaseVoucher(double amt, Dept dept, PartyRole company, PartyRole partner, LossSaleAdjust lossSaleAdjust){
        Voucher voucher = getVoucher(lossSaleAdjust);
        voucher.setBusinessType(BusinessType.PURCHASE_ORDER);
        voucher.setDept(dept);
        voucher.setCompany(company);
        voucher.setPartner(partner.getParty().getPartyRoleByType("Supplier"));

        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = getVoucherItem(lossSaleAdjust);
        voucherItem.setPriceUnit(amt);
        voucherItem.setProductQty(1);
        voucherItem.setOwner(company);

        Tax tax = taxService.getPurchaseTax(company, voucher.getPartner(), voucherItem.getProduct());   //供应商进项税
        voucherItem.setTax(tax);

        voucherItems.add(voucherItem);
        voucher.setVoucherItems(voucherItems);

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        if (amt > 0) {
            invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));
        }

        // 冻结批次
        frostQty(voucher, voucherItem);
        return voucher;
    }

    private void frostQty(Voucher purVoucher, VoucherItem voucherItem) {
        VoucherItem purVoucherItem = purVoucher.getVoucherItems().iterator().next();    // 由于只有一个商品，这里获取第一个元素
        VoucherInventory voucherInventory = voucherInventoryRepository.findByVoucherItem(purVoucherItem).stream()
                .findAny().orElseThrow(() -> new RuntimeException("找不到批次信息！"));
        InventoryBatch inventoryBatch = voucherInventory.getInventoryBatch();

        inventoryService.changeFrostQty(inventoryBatch, inventoryBatch.getUom(), inventoryBatch.getPurchaseQty(),
                purVoucher.getCompany(), purVoucher.getInnerBusinessType(), purVoucher.getId(),
                String.valueOf(voucherItem.getId()), "定损调整单重新采购, 冻结批次数量");
    }

    private void createSaleVoucher(Voucher purVoucher, PartyRole partner, LossSaleAdjust lossSaleAdjust){
        Voucher voucher = getVoucher(lossSaleAdjust);
        voucher.setBusinessType(BusinessType.SALE_ORDER);
        voucher.setDept(purVoucher.getDept());
        voucher.setCompany(purVoucher.getCompany());
        voucher.setPartner(partner.getParty().getPartyRoleByType("Customer"));
        voucher.setClassification(VoucherType.LOSS_SALE_RETURN);

        Set<VoucherItem> voucherItems = new HashSet<>(1);
        VoucherItem voucherItem = getVoucherItem(lossSaleAdjust);
        voucherItem.setPriceUnit(lossSaleAdjust.getAmount());
        voucherItem.setProductQty(1);
        voucherItem.setOwner(purVoucher.getCompany());

        Tax tax = taxService.getSaleTax(purVoucher.getCompany(), voucherItem.getProduct());
        voucherItem.setTax(tax);

        // 指定批次数据
        VoucherInventory vi = voucherInventoryRepository.findByVoucherItem(purVoucher.getVoucherItems().iterator().next()).stream().findFirst()
                .orElseThrow(() -> new RuntimeException("生成对保险公司销售时，没有找到对应的凭证批次数据!"));
        voucherItem.setInventoryBatch(vi.getInventoryBatch());

        voucherItems.add(voucherItem);
        voucher.setVoucherItems(voucherItems);

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));
    }
}
